﻿namespace Pub.Class
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Threading;

    public static class TypeExtensions
    {
        private static readonly ISafeDictionary<Type, Dictionary<string, PropertyInfo>> t_cache = new SafeDictionarySlim<Type, Dictionary<string, PropertyInfo>>();
        private static readonly ISafeDictionary<Type, PropertyInfo[]> t_cache2 = new SafeDictionarySlim<Type, PropertyInfo[]>();

        public static object CreateInstance(this Type type, params object[] constructorParameters)
        {
            return type.CreateInstance<object>(constructorParameters);
        }

        public static T CreateInstance<T>(this Type type, params object[] constructorParameters)
        {
            return (T) Activator.CreateInstance(type, constructorParameters);
        }

        public static MemberInfo FindMember(this Type classType)
        {
            return classType.FindMembers().ToList<MemberInfo>()[0];
        }

        public static IEnumerable<MemberInfo> FindMembers(this Type type)
        {
            foreach (PropertyInfo iteratorVariable0 in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
            {
                MethodInfo getMethod = iteratorVariable0.GetGetMethod(true);
                MethodInfo setMethod = iteratorVariable0.GetSetMethod(true);
                if ((!getMethod.IsNull() && !getMethod.IsPrivate) && (!setMethod.IsNull() && (setMethod.GetParameters().Length == 1)))
                {
                    yield return iteratorVariable0;
                }
            }
            foreach (FieldInfo iteratorVariable3 in type.GetFields())
            {
                if (!iteratorVariable3.IsInitOnly && !iteratorVariable3.IsLiteral)
                {
                    yield return iteratorVariable3;
                }
            }
        }

        public static PropertyInfo[] GetPropertiesCache(this Type type)
        {
            if (!t_cache2.ContainsKey(type))
            {
                PropertyInfo[] properties = type.GetProperties();
                t_cache2[type] = properties;
                return properties;
            }
            return t_cache2[type];
        }

        public static PropertyInfo GetPropertyCache(this Type type, string propertyName)
        {
            if (!t_cache.ContainsKey(type))
            {
                t_cache[type] = new Dictionary<string, PropertyInfo>();
            }
            if (!t_cache[type].ContainsKey(propertyName))
            {
                PropertyInfo property = type.GetProperty(propertyName);
                t_cache[type][propertyName] = property;
                return property;
            }
            return t_cache[type][propertyName];
        }

        public static bool IsNullable(this Type t)
        {
            return (!t.IsSubclassOf(typeof(System.ValueType)) || (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(Nullable<>))));
        }

        public static bool IsSystemType(this Type type)
        {
            if (((((type != typeof(string)) && (type != typeof(short))) && ((type != typeof(short?)) && (type != typeof(int)))) && (((type != typeof(int?)) && (type != typeof(long))) && ((type != typeof(long?)) && (type != typeof(decimal))))) && ((((type != typeof(decimal?)) && (type != typeof(double))) && ((type != typeof(double?)) && (type != typeof(DateTime)))) && (((type != typeof(DateTime?)) && (type != typeof(Guid))) && ((type != typeof(Guid?)) && (type != typeof(bool))))))
            {
                return (type == typeof(bool?));
            }
            return true;
        }

        public static DbType ToDbType(this Type type)
        {
            if (type == typeof(int))
            {
                return DbType.Int32;
            }
            if (type == typeof(short))
            {
                return DbType.Int16;
            }
            if (type == typeof(long))
            {
                return DbType.Int64;
            }
            if (type == typeof(DateTime))
            {
                return DbType.DateTime;
            }
            if (type == typeof(float))
            {
                return DbType.Decimal;
            }
            if (type == typeof(decimal))
            {
                return DbType.Decimal;
            }
            if (type == typeof(double))
            {
                return DbType.Double;
            }
            if (type == typeof(Guid))
            {
                return DbType.Guid;
            }
            if (type == typeof(bool))
            {
                return DbType.Boolean;
            }
            if (type == typeof(byte[]))
            {
                return DbType.Byte;
            }
            return DbType.String;
        }

        public static string ToMySqlType(this DbType dbType)
        {
            switch (dbType)
            {
                case DbType.AnsiString:
                case DbType.Object:
                case DbType.String:
                case DbType.AnsiStringFixedLength:
                case DbType.StringFixedLength:
                    return "nvarchar";

                case DbType.Binary:
                case DbType.Byte:
                case DbType.SByte:
                    return "longblob";

                case DbType.Boolean:
                    return "tinyint";

                case DbType.Currency:
                    return "money";

                case DbType.Date:
                case DbType.DateTime:
                case DbType.Time:
                    return "datetime";

                case DbType.Decimal:
                    return "decimal";

                case DbType.Double:
                    return "float";

                case DbType.Guid:
                    return "binary";

                case DbType.Int16:
                case DbType.Int32:
                case DbType.Int64:
                case DbType.UInt16:
                case DbType.UInt32:
                case DbType.UInt64:
                    return "int";

                case DbType.Single:
                    return "real";

                case DbType.VarNumeric:
                    return "numeric";

                case DbType.Xml:
                    return "xml";
            }
            return "nvarchar";
        }

        public static string ToSql2005Type(this DbType dbType)
        {
            switch (dbType)
            {
                case DbType.AnsiString:
                case DbType.Object:
                case DbType.String:
                case DbType.AnsiStringFixedLength:
                case DbType.StringFixedLength:
                    return "nvarchar";

                case DbType.Binary:
                case DbType.Byte:
                case DbType.SByte:
                    return "image";

                case DbType.Boolean:
                    return "bit";

                case DbType.Currency:
                    return "money";

                case DbType.Date:
                case DbType.DateTime:
                case DbType.Time:
                    return "datetime";

                case DbType.Decimal:
                    return "decimal";

                case DbType.Double:
                    return "float";

                case DbType.Guid:
                    return "uniqueidentifier";

                case DbType.Int16:
                case DbType.Int32:
                case DbType.Int64:
                case DbType.UInt16:
                case DbType.UInt32:
                case DbType.UInt64:
                    return "int";

                case DbType.Single:
                    return "real";

                case DbType.VarNumeric:
                    return "numeric";

                case DbType.Xml:
                    return "xml";
            }
            return "nvarchar";
        }

        public static SqlDbType ToSqlDBType(this DbType dbType)
        {
            switch (dbType)
            {
                case DbType.AnsiString:
                    return SqlDbType.VarChar;

                case DbType.Binary:
                    return SqlDbType.VarBinary;

                case DbType.Byte:
                    return SqlDbType.TinyInt;

                case DbType.Boolean:
                    return SqlDbType.Bit;

                case DbType.Currency:
                    return SqlDbType.Money;

                case DbType.Date:
                    return SqlDbType.DateTime;

                case DbType.DateTime:
                    return SqlDbType.DateTime;

                case DbType.Decimal:
                    return SqlDbType.Decimal;

                case DbType.Double:
                    return SqlDbType.Float;

                case DbType.Guid:
                    return SqlDbType.UniqueIdentifier;

                case DbType.Int16:
                    return SqlDbType.Int;

                case DbType.Int32:
                    return SqlDbType.Int;

                case DbType.Int64:
                    return SqlDbType.BigInt;

                case DbType.Object:
                    return SqlDbType.Variant;

                case DbType.SByte:
                    return SqlDbType.TinyInt;

                case DbType.Single:
                    return SqlDbType.Real;

                case DbType.String:
                    return SqlDbType.NVarChar;

                case DbType.Time:
                    return SqlDbType.DateTime;

                case DbType.UInt16:
                    return SqlDbType.Int;

                case DbType.UInt32:
                    return SqlDbType.Int;

                case DbType.UInt64:
                    return SqlDbType.BigInt;

                case DbType.VarNumeric:
                    return SqlDbType.Decimal;

                case DbType.AnsiStringFixedLength:
                    return SqlDbType.Char;

                case DbType.StringFixedLength:
                    return SqlDbType.NChar;
            }
            return SqlDbType.VarChar;
        }

        public static string ToSQLiteType(this DbType dbType)
        {
            switch (dbType)
            {
                case DbType.AnsiString:
                case DbType.Object:
                case DbType.String:
                case DbType.AnsiStringFixedLength:
                case DbType.StringFixedLength:
                    return "nvarchar";

                case DbType.Binary:
                case DbType.Byte:
                case DbType.SByte:
                    return "longblob";

                case DbType.Boolean:
                    return "tinyint";

                case DbType.Currency:
                    return "money";

                case DbType.Date:
                case DbType.DateTime:
                case DbType.Time:
                    return "datetime";

                case DbType.Decimal:
                    return "decimal";

                case DbType.Double:
                    return "float";

                case DbType.Guid:
                    return "guid";

                case DbType.Int16:
                case DbType.UInt16:
                    return "tinyint";

                case DbType.Int32:
                case DbType.UInt32:
                    return "int";

                case DbType.Int64:
                case DbType.UInt64:
                    return "integer";

                case DbType.Single:
                    return "real";

                case DbType.VarNumeric:
                    return "numeric";

                case DbType.Xml:
                    return "xml";
            }
            return "nvarchar";
        }

    }
}

